#!/usr/bin/env python
# -*- coding: utf8 -*-
#-------------------------------------------------------------------------------
# Name:        actor_yield.py
# Purpose:    use python to emulate a actor design pattern
#
# Author:      iori
#
# Created:     01/11/2014
# Copyright:   (c) iori 2014
# Licence:     GPLv3
#-------------------------------------------------------------------------------

from concurrent.futures import ThreadPoolExecutor,  Future, ProcessPoolExecutor
from collections import deque


_registry = {}  # all actors name:actor dict
_msg_queue = deque()

def run():
    while _msg_queue:
        target, msg = _msg_queue.popleft()
        try:
            _registry[target].send(msg)
        except KeyError as e:
            print(e)

def actor(func):
    ''' make a function become an actor '''
    def _wrapper(*nkw, **kw):
        g = func(*nkw, **kw)
        next(g)
        _registry[func.__name__] = g
    return _wrapper

def send(target, msg):
    _msg_queue.append((target, msg))

@actor
def printer():
    while True:
        msg = yield
        print('printer: ', msg)


@actor
def ping():
    while True:
        n = yield
        print('ping  get: ', n)
        send('pong', n+1)   # pong.send(n+1)

@actor
def pong():
    while True:
        n = yield
        print('pong get: ', n)
        send('ping', n+1)   # ping.send(n+1)

printer()
ping()
pong()
for i in range(10):
    send('printer', i)

send('copy', 3)
send('ping', 1)

run() # some kind of event loop